/**
 * 将 Animation 模块拆分为 SlideAnimation 与 ShapeAnimation
 *  SlideAnimation 专注于处理幻灯片切换动画
 *  ShapeAnimation 专注于处理图形动画
 *
 *  1. 切换动画通过 css animation 实现
 *   1.1 应用在 konvajs-content 上
 *   1.2 对于 animation 来说，动画就是个类名，通过 style 来设置动画
 *   1.3 动画结束后，需要移除动画类名，通过 style.animation = '' 实现
 *   1.4 动画应用是通过 Layer.setAttrs 记录状态，在预览时，动态添加即可
 *
 *  2. 切换应用动画的流程：
 *    2.1 调用 setAnimation 给当前layer标记动画属性；
 *    2.2 在预览时 调用 applyAnimation 应用动画；
 *    2.3 动画结束后，调用clearTimeOut清除动画
 *    2.4 如果是应用全部动画的话，通过 global 标识，每次新增幻灯片，都判断有没有全局动画，如果有，则应用全局动画
 */

import { Draw } from "./Draw";
import { nextTick } from "../Utils";
import { ISlideAnimation } from "../Interface/Animation";

export class SlideAnimation {
  private draw: Draw;
  private timer: number | null = null;
  private globalAnimation: null | ISlideAnimation = null;

  constructor(draw: Draw) {
    this.draw = draw;
  }

  /** 设置 Layer 切换动画 */
  public setAnimation(payload: ISlideAnimation) {
    const layer = this.draw.getLayer();

    if (!layer) return;

    // 这里是在做一次演示效果
    const root = this.draw.getRootBox();
    type HDE = HTMLDivElement;
    const konvajsContent = <HDE>root.querySelector(".konvajs-content");

    if (this.timer) {
      konvajsContent!.style.animation = "";
      clearTimeout(this.timer);
    }

    const { delay = 0, duration = 1000, name, global = false } = payload;

    if (global) {
      // 1. 存储全局动画
      this.globalAnimation = payload;
      // 2. 重新刷新全局动画
      const layerManager = this.draw.getLayerManager();
      const layerlist = layerManager.getLayerList();
      layerlist.forEach((layer) => {
        layer.setAttrs({
          animation: name,
          animationDuration: duration,
          animationDelay: delay,
        });
      });
    }

    // 不管是不是全局动画，都需要设置当前动画，因为 当前动画还没有更新到 layerlist 中
    layer.setAttrs({
      animation: name,
      animationDuration: duration,
      animationDelay: delay,
    });

    konvajsContent!.style.animation = `alternate ${name} ${duration}ms ease-in-out`;
    // 应用成功提示
    this.draw.getMessage().success("幻灯片切换动画应用成功！");

    this.timer = setTimeout(() => {
      konvajsContent!.style.animation = "";
      if (this.timer) clearTimeout(this.timer);
    }, duration) as unknown as number;
  }

  /** 解析应用动画 */
  public applyAnimation() {
    nextTick(() => {
      const layer = this.draw.getLayer();
      if (!layer) return;

      const { animation, animationDuration } = layer.getAttrs();
      if (!animation || !layer) return;

      const root = this.draw.getRootBox();
      type HDE = HTMLDivElement;
      const konvajsContent = <HDE>root.querySelector(".konvajs-content");

      if (this.timer) {
        konvajsContent!.style.animation = "";
        clearTimeout(this.timer);
      }

      konvajsContent!.style.animation = `alternate ${animation} ${animationDuration}ms ease-in-out`;

      this.timer = setTimeout(() => {
        konvajsContent!.style.animation = "";
        if (this.timer) clearTimeout(this.timer);
      }, animationDuration) as unknown as number;
    });
  }

  /** 解决应用某个动画为全部动画，后面创建的 slide 也应用该动画 */
  public triggerGlobalAnimation() {
    if (!this.globalAnimation) return;
    this.setAnimation(this.globalAnimation);
  }

  // 取消动画
  public cancelAnimation(payload?: { global: boolean }) {
    if (payload && payload.global) {
      this.globalAnimation = null;
      // 2. 重新刷新全局动画
      const layerManager = this.draw.getLayerManager();
      const layerlist = layerManager.getLayerList();
      layerlist.forEach((layer) => {
        layer.setAttrs({
          animation: null,
          animationDuration: null,
          animationDelay: null,
        });
      });
    } else {
      const layer = this.draw.getLayer();
      if (!layer) return;
      layer.setAttrs({
        animation: null,
        animationDuration: null,
        animationDelay: null,
      });
    }
  }
}
